/*
 *
 *  *    Copyright 2020-2021 luter.me
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *      http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.luter.heimdall.core.context;

import com.luter.heimdall.core.config.ConfigManager;
import com.luter.heimdall.core.config.HeimdallProperties;
import com.luter.heimdall.core.config.options.ResolveTokenOptions;
import com.luter.heimdall.core.config.options.TokenTypeOptions;
import com.luter.heimdall.core.exception.HeimdallException;
import com.luter.heimdall.core.exception.HeimdallInvalidTokenException;
import com.luter.heimdall.core.utils.StrUtils;

/**
 * web request 请求功能定义
 *
 * @author luter
 */
public interface WebRequestHolder {

    /**
     * 获取 request 中的 cookie 值
     *
     * @param name the name，cookie 名称
     * @return the cookie value cookie 值
     */
    String getCookieValue(String name);

    /**
     * 获取 request 中的 cookie 值
     *
     * @param name         the name，cookie 名称
     * @param defaultValue 默认值
     * @return the cookie value cookie 值
     */
    default String getCookieValue(String name, String defaultValue) {
        final String cookieValue = getCookieValue(name);
        return StrUtils.isBlank(cookieValue) ? defaultValue : cookieValue;
    }

    /**
     * 从 request header 中获取参数值
     *
     * @param name the name 参数名称
     * @return the header value 参数值
     */
    String getHeaderValue(String name);

    /**
     * 从 request header 中获取参数值
     *
     * @param name         the name 参数名称
     * @param defaultValue 默认值
     * @return the header value 参数值
     */
    default String getHeaderValue(String name, String defaultValue) {
        final String headerValue = getHeaderValue(name);
        return StrUtils.isBlank(headerValue) ? defaultValue : headerValue;
    }

    /**
     * 从 request query 中获取参数值
     *
     * @param name the name 参数名称
     * @return the query value 参数值
     */
    String getQueryValue(String name);

    /**
     * 从 request query 中获取参数值
     *
     * @param name         the name 参数名称
     * @param defaultValue 默认值
     * @return the query value 参数值
     */
    default String getQueryValue(String name, String defaultValue) {
        final String queryValue = getQueryValue(name);
        return StrUtils.isBlank(queryValue) ? defaultValue : queryValue;

    }

    /**
     * 获取请求路径 ,如 /user/1
     *
     * @return the request uri 请求路径
     */
    String getRequestURI();

    /**
     * .获取请求 QueryString 串
     * <p>
     * 请求路径后带的所有参数字符串，如:"x?name=1&age=10"
     *
     * @return the query string
     */
    String getQueryString();

    /**
     * 获取请求方法，GET POST 等
     *
     * @return the method
     */
    String getMethod();

    /**
     * 获取客户端真实 IP
     *
     * @return the remote ip
     */
    String getRemoteIp();

    /**
     * 从请求中解析 token 值
     *
     * @return the string
     */
    default String resolveToken() {
        HeimdallProperties config = ConfigManager.getConfig();
        final ResolveTokenOptions resolveTokenOptions = config.getToken().getTokenFrom();
        final String tokenName = config.getToken().getName();
        final String resolverTokenPrefix = config.getToken().getTokenPrefix();
        String token;
        //按配置获取
        switch (resolveTokenOptions) {
            case COOKIE:
                token = getCookieValue(tokenName);
                break;
            case HEADER:
                token = getHeaderValue(tokenName);
                break;
            case QUERY:
                token = getQueryValue(tokenName);
                break;
            case HEADER_OR_QUERY:
                token = getHeaderValue(tokenName);
                if (StrUtils.isBlank(token)) {
                    token = getQueryValue(tokenName);
                }
                break;
            case ALL:
                //开启了 cookie 而且 cookieName 不为空就从 cookie 拿，否则从 header 拿
                token = getCookieValue(tokenName);
                if (StrUtils.isBlank(token)) {
                    token = getHeaderValue(tokenName);
                    //cookie 和 header 都没有，从 url query 拿
                    if (StrUtils.isBlank(token)) {
                        token = getQueryValue(tokenName);
                    }
                }
                break;
            default:
                //ResolveTokenOptions这玩意配置错了
                throw new IllegalStateException("Unexpected value of  ResolveTokenOptions : " + resolveTokenOptions);
        }
        //去掉前缀，拿出 token 本体，看看是不是 jwt 编码的串
        if (config.getToken().getType().equals(TokenTypeOptions.JWT) && StrUtils.isNotBlank(token)) {
            String tokenBody = token;
            if (token.startsWith(resolverTokenPrefix)) {
                tokenBody = token.replaceFirst(resolverTokenPrefix, "");
            }
            if (StrUtils.isNotValidJwtToken(tokenBody)) {
                throw new HeimdallException("It seems that this token: [" + tokenBody + "] is not a legal JWT token?");
            }
        }
        //有前缀
        if (StrUtils.isNotBlank(resolverTokenPrefix) && StrUtils.isNotBlank(token)) {
            //传来的 token 以 前缀开始，去掉前缀，后去掉前后空格
            if (token.startsWith(resolverTokenPrefix)) {
                //前后空格去掉
                token = token.replaceFirst(resolverTokenPrefix, StrUtils.EMPTY_STRING).trim();
            }
            //配置里前缀，但是接收到的 token 却没有前缀，前缀不匹配，异常
            else {
                throw new HeimdallInvalidTokenException(HeimdallInvalidTokenException.DEFAULT_MESSAGE + ",Bad prefix.");
            }
        }
        return token;
    }

}
